#pragma once
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

#define MySelf 0 // 去掉注释就是用我们自己的序列化和反序列化，加上注释就是用json库提供的

const std::string blank_space = " "; // 分隔符
const std::string protocol_sep = "\n";

std::string Encode(const std::string &content) // 添加报头
{
    std::string packge = std::to_string(content.size()); // 加报头
    packge += protocol_sep;                              // 加\n
    packge += content;                                   // 加正文
    packge += protocol_sep;                              // 再加\n

    return packge;
}

bool Decode(std::string &package, std::string *content) // 解析并去掉报头 "9"\n"10 + 20"\n -->"10 + 20"  俗称解包，但是只是去掉了报头，没有做报文的具体解析
{
    std::size_t pos = package.find(protocol_sep); // 找到\n的左边
    if (pos == std::string::npos)
        return false;                             // 解析失败
    std::string len_str = package.substr(0, pos); // 从开始截到我找到的\n处，把前面的9给截出来
    std::size_t len = std::stoi(len_str);         // 把截出来的报头转化为size_t，也就是把字符串9转化成数字9

    // packge的长度 = 报头长度len_str + 有效载荷长度content_str + 两个\n 2
    std::size_t total_len = len_str.size() + len + 2;
    // ①找到了第一个\n说明一定有长度，如果没找到\n就说明连报头都没有
    // ②有了长度报头，你也还得保证后面的内容也是完整的，如果不完整也就是长度不一样，那我也就不玩了
    if (package.size() < total_len)
        return false;

    // 走到这一步说明我们能保证报文是完整的，开始拿有效载荷
    *content = package.substr(pos + 1, len); // pos现在是第一个\n左边的位置，+1后面的就是正文内容，正文内容长度为len

    // 移除一个报文，该功能需要和网络相结合
    package.erase(0, total_len);

    return true;
}

class Request // 计算的请求
{
public:
    Request(int data1, int data2, char oper)
        : x(data1), y(data2), op(oper)
    {
    }
    Request()
    {
    }
    ~Request()
    {
    }

public:
    bool Serialize(std::string *out) // 序列化
    {
#ifdef MySelf
        // 1，构建报文的有效载荷
        //  需要把结构化的数据转化为字符串 struct --> string, "x op y"
        std::string s = std::to_string(x);
        s += blank_space;
        s += op;
        s += blank_space;
        s += std::to_string(y);
        // 走到这里的时候就是字符串 "x op y"
        // 但是在传输的时候可能发过来的不是完整的一个报文："10 + 20"，而是只有半个报文："10 + "
        // 解决方案一：用特殊字符隔开报文与报文 --> "10 + 20" \n "20 + 40"
        // 解决方案二：再在报文前面加一个字符串的长度也就是报头，例如s.size()
        // 结合起来就是"9"\n"100 + 200"\n，为一个完整的报文，其实只要有长度就可以了，这里增加\n是为了可读性，也是为了方便后面打印

        // 2，封装报头
        *out = s;
        return true;
#else
        Json::Value root;
        root["x"] = x;
        root["y"] = y;
        root["op"] = op;
        Json::FastWriter w;
        *out = w.write(root);
        return true;

#endif
    }
    bool DeSerialize(const std::string &in) // 反序列化  "9"\n"10 + 20"
    {
#ifdef MySelf
        std::size_t left = in.find(blank_space); // 找空格的左边，"10 + 20"，也就是找10的右边位置
        if (left == std::string::npos)           // 没找到空格，说明当前解析错误
        {
            return false;
        }
        std::string part_x = in.substr(0, left); // 截取第一个数字，也就是10

        std::size_t right = in.rfind(blank_space); // 逆向再次找空格，"10 + 20"，找20左边的位置
        if (right == std::string::npos)            // 没找到空格，说明当前解析错误
        {
            return false;
        }
        std::string part_y = in.substr(right + 1); // 截取后面的数字，也就是20，+1是因为找到的是空格的右边，+1跳过空格才是数字部分
        if (left + 2 != right)
            return false;  // 数字中间还有运算符，所以left+2就应该是right的左边那个空格的左边位置，如果不是那么就是解析错误
        op = in[left + 1]; // 拿到运算符
        // op = in[right - 1]; //一样的

        x = std::stoi(part_x); // 拿到数字
        y = std::stoi(part_y);

        return true;
#else
        Json::Value root;
        Json::Reader r;
        r.parse(in, root);

        x = root["x"].asInt();
        y = root["y"].asInt();
        op = root["op"].asInt();
        return true;
#endif
    }
    void DebugPrint()
    {
        std::cout << "新请求构建完成:  " << x << " " << op << " " << y << "=?" << std::endl;
    }

public:
    int x;
    int y;
    char op; // 运算符
};

class Response // 计算的应答
{
public:
    Response(int res, int c)
        : result(res), code(c)
    {
    }
    Response()
    {
    }
    ~Response()
    {
    }

public:
    bool Serialize(std::string *out) // 序列化
    {
#ifdef MySelf
        // 1，构建报文的有效载荷
        //"len"\n"result code"
        std::string s = std::to_string(result);
        s += blank_space;
        s += std::to_string(code);

        *out = s;
        return true;
#else
        Json::Value root;
        root["result"] = result;
        root["code"] = code;
        // Json::FastWriter w;
        Json::StyledWriter w;
        *out = w.write(root);
        return true;
#endif
    }
    bool DeSerialize(const std::string &in) // 反序列化
    {
#ifdef MySelf
        // 对服务器发过来的结果报文做解析: "result code"
        std::size_t pos = in.find(blank_space); // 找空格的左边
        if (pos == std::string::npos)           // 没找到空格，说明当前解析错误
        {
            return false;
        }
        std::string part_left = in.substr(0, pos);   // 截取第一个数字，也就是result
        std::string part_right = in.substr(pos + 1); // 截取后面第二个数字，也就是code

        result = std::stoi(part_left);
        code = std::stoi(part_right);
        return true;
#else
        Json::Value root;
        Json::Reader r;
        r.parse(in, root);
        result = root["result"].asInt();
        code = root["code"].asInt();
        return true;
#endif
    }

    void DebugPrint()
    {
        std::cout << "结果响应完成, result: " << result << ", code: " << code << std::endl;
    }

public:
    int result; // x op y
    int code;   // 错误码，为0时结果正确，为其它数时对应的数表示对应的原因
};